/**********************************************************************************************************************
 *
 * Project:    mGameEngine
 * File:       distancejoint.cpp
 * Author:     karooolek
 * Created on: Nov 9, 2009
 *
 **********************************************************************************************************************/

#include "distancejoint.h"

namespace mGameEngine
{
namespace Physics
{

DistanceJoint::DistanceJoint(float minDistance, float maxDistance, float spring, float damp) :
    Joint(),
    _minDistance(minDistance), _maxDistance(maxDistance), _spring(spring), _damp(damp)
{
}

DistanceJoint::~DistanceJoint()
{
    // everything done in ~Joint()
}

void DistanceJoint::setMinimalDistance(float minDistance)
{
    // minimal distance must be between 0.0 and maximal distance
    if(minDistance < 0.0f || minDistance > _maxDistance)
    {
        return;
    }

    _minDistance = minDistance;

    if(_joint)
    {
        NxDistanceJoint *distJoint = (NxDistanceJoint *)_joint;
        NxDistanceJointDesc desc;
        distJoint->saveToDesc(desc);
        desc.flags |= NX_DJF_MIN_DISTANCE_ENABLED;
        desc.minDistance = _minDistance;
        distJoint->loadFromDesc(desc);
    }
}

void DistanceJoint::setMaximalDistance(float maxDistance)
{
    // max distance must be greater or equal to minimal distance
    if(maxDistance < _minDistance)
    {
        return;
    }

    _maxDistance = maxDistance;

    if(_joint)
    {
        NxDistanceJoint *distJoint = (NxDistanceJoint *)_joint;
        NxDistanceJointDesc desc;
        distJoint->saveToDesc(desc);
        desc.flags |= NX_DJF_MAX_DISTANCE_ENABLED;
        desc.maxDistance = _maxDistance;
        distJoint->loadFromDesc(desc);
    }
}

void DistanceJoint::setSpring(float spring)
{
    // spring constant must be positive
    if(spring < 0.0f)
    {
        return;
    }

    _spring = spring;

    if(_joint)
    {
        // TODO
    }
}

void DistanceJoint::setDamping(float damp)
{
    // damping coefficient must be between 0.0 and 1.0
    if(damp < 0.0f || damp > 1.0f)
    {
        return;
    }

    _damp = damp;

    if(_joint)
    {
        // TODO
    }
}

void DistanceJoint::create(NxActor *actor1, NxActor *actor2) const
{
    // two actors required
    if(!actor1 || !actor2)
    {
        return;
    }

    // already created
    if(_created)
    {
        return;
    }

    // create joint
    NxDistanceJointDesc desc;

    // assign first actor
    if(actor1->isDynamic())
    {
        desc.actor[0] = actor1;
        desc.localAnchor[0] = NxVec3(_anchor1.m[3]);
    }
    else
    {
        desc.actor[0] = NULL;
        desc.localAnchor[0] = actor1->getGlobalPose() * NxVec3(_anchor1.m[3]);
    }

    // assign second actor
    if(actor2->isDynamic())
    {
        desc.actor[1] = actor2;
        desc.localAnchor[1] = NxVec3(_anchor2.m[3]);
    }
    else
    {
        desc.actor[1] = NULL;
        desc.localAnchor[1] = actor2->getGlobalPose() * NxVec3(_anchor2.m[3]);
    }

    if(_minDistance > 0.0f)
    {
        desc.flags |= NX_DJF_MIN_DISTANCE_ENABLED;
        desc.minDistance = _minDistance;
    }

    if(_maxDistance >= 0.0f && _maxDistance >= _minDistance)
    {
        desc.flags |= NX_DJF_MAX_DISTANCE_ENABLED;
        desc.maxDistance = _maxDistance;
    }

    if(_spring > 0.0f)
    {
        desc.flags |= NX_DJF_SPRING_ENABLED;
        desc.spring.spring = _spring;
        desc.spring.damper = _damp;
    }

    _joint = actor1->getScene().createJoint(desc);

    // problems while creating joint
    if(!_joint)
    {
        return;
    }

    // joint is created
    _created = true;
}

}
}

